home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel Volume 2 #1
/
carousel.iso
/
mactosh
/
util
/
sortmenu.sit
/
SortMenu Code
next >
Wrap
Text File
|
1985-08-16
|
6KB
|
247 lines
; File SortMenu.TXT
;--------------------------------------------------------------------
;
; This program installs code in the system heap that patches out
; AddResMenu so it returns with the added names sorted in alphabetical
; order. It works internationally, since it uses Pack6 for the
; string compare.
;
; written by Andy Hertzfeld 04-Aug-85 (in the big Apple)
;
;--------------------------------------------------------------------
INCLUDE MacTraps.D
XDEF START
START
BRA InstallIt
AddResPatch
LEA theMenuHandle,A0 ;get locals address
MOVE.L 8(SP),A1 ;get menu handle
MOVE.L A1,(A0)+ ;remember menu handle
MOVE.L (SP)+,(A0) ;remember return address
SUBQ #2,SP
MOVE.L A1,-(SP) ;push the menu handle
_CountMItems ;count the items
LEA baseItem,A0
MOVE.W (SP)+,(A0) ;remember # of items
; now run the old routine
MOVE.L OldARMenu,A0 ;get old routine
JSR (A0) ;invoke it
; allocate work space and save registers
LINK A6,#-260 ;space for string plus 4
MOVEM.L D3-D6/A2-A4,-(SP) ;save some work registers
; load Pack6 into memory
SUBQ #4,SP
MOVE.L #$5041434B,-(SP) ;push PACK
MOVE #6,-(SP) ;pack 6
_GetResource ;load it in
ADDQ #4,SP
; now count the # of items now in the menu and compute how many were added
SUBQ #2,SP ;reserve space for result
MOVE.L theMenuHandle,A2 ;keep menuHandle in A2
MOVE.L A2,-(SP) ;push it
_CountMItems ;count em up
MOVE.W (SP)+,D3 ;keep # of items in D3
MOVE.W BaseItem,D4 ;keep base items in D4
MOVE D3,D5 ;copy item count
SUB D4,D5 ;compute # of new items
BEQ DoneARMenu ;if none, we're done
; OK, now we're ready to do the real work. A3 will point to the current
; item we're bubbling. First, skip to it.
MOVE.L (A2),A3 ;start at the beginning
ADD.W #14,A3 ;skip header
MOVEQ #0,D0 ;clear out high part
MOVE.B (A3)+,D0 ;get title length
ADD.W D0,A3 ;skip over it
; skip the number of items in D4
BRA.S NextSkipBase
SkipBaseLoop
MOVE.B (A3),D0 ;get item length
ADD.W D0,A3 ;skip item
ADDQ.W #5,A3 ;skip length, prop bytes
NextSkipBase
DBRA D4,SkipBaseLoop
; remember the first item we're starting with
MOVE.L A3,A4
; here's the sort loop. Compare the current item with the next one and,
; if it's lexically greater, swap them
SortLoop0
MOVE.L A4,A3 ;start with first one
SortLoop1
MOVEQ #0,D0
MOVE.B (A3),D0
LEA 5(A3,D0),A0 ;compute next one
MOVE.L A0,D6 ;remember for later
TST.B (A0) ;is it the last?
BEQ.S NextIteration ;if so, skip
; use Pack6 for the string compare
MOVE.L A3,A1
SUBQ #2,SP ;reserve space for result
MOVEQ #0,D1
MOVEQ #0,D2
MOVE.B (A1)+,D1 ;get 1st length
; if it begins with null, skip it
TST.B (A1)
BNE.S @0
ADDQ #1,A1
SUBQ #1,D1
@0
MOVE.L A1,-(SP) ;push string
MOVE.B (A0)+,D2 ;get 2nd length
; ditto for second string
TST.B (A0)
BNE.S @1
ADDQ #1,A0
SUBQ #1,D2
@1
MOVE.L A0,-(SP) ;push string
MOVE.W D1,-(SP) ;push 1st length
MOVE.W D2,-(SP) ;push 2nd string
MOVE.W #10,-(SP) ;push selector
_Pack6 ;invoke string compare
MOVE.W (SP)+,D0 ;get result
BLE.S NextItem ;if in order, skip
; the first item is greater than the second, so swap them. First move
; first item into a temporary location
MOVE.L A3,A0 ;source address
BSR.S GetSourceLen
LEA -256(A6),A1 ;destination
_BlockMove
; move the second item over the first
MOVE.L D6,A0 ;source address
MOVE.L A3,A1 ;destination address
BSR.S GetSourceLen
_BlockMove
; move the first back in
LEA -256(A6),A0 ;source address
MOVEQ #0,D0
MOVE.B (A3),D0
LEA 5(A3,D0),A1 ;destination address
MOVE.L A1,D6 ;new next item
BSR.S GetSourceLen
_BlockMove
; now try the next item, bubbling down until we've reached the bottom
NextItem
MOVE.L D6,A3 ;point A3 to next item
BRA.S SortLoop1 ;go put it in order
; GetSourceLen is a utility that returns the length of the string pointed
; to by A0 plus 5 in D0.
GetSourceLen
MOVEQ #0,D0 ;clear D0
MOVE.B (A0),D0 ;get the length
ADDQ #5,D0 ;include length, prop bytes
RTS
; NextIteration is the bottom of the outer loop. Repeat it enough times
; until it's sorted
NextIteration
SUBQ #1,D5 ;more to do?
BGT.S SortLoop0 ;if so, go do it
; we're all done so deallocate storage, restore registers and return
DoneARMenu
MOVEM.L (SP)+,D3-D6/A2-A4 ;restore work registers
UNLK A6 ;release stack frame
MOVE.L theReturnAddress,A0 ;recover return address
JMP (A0) ;bye-bye!
; our local variables
theMenuHandle
DC.W 0,0
theReturnAddress
DC.W 0,0
BaseItem
DC.W 0
OldARMenu
DC.W 0,0
; InstallIt is the routine that installs the above in the system heap
InstallIt
; get the address of the current AddResMenu routine and remember it
MOVE.W #$14D,D0 ;trap ID of AddResMenu
_GetTrapAddress ;get old address
LEA OldARMenu,A1
MOVE.L A0,(A1) ;remember old address
; compute size of code and allocate in system heap, then move it in
LEA AddResPatch,A2
LEA InstallIt,A0
MOVE.L A0,D0
SUB.L A2,D0 ;compute size
MOVE.L D0,D1 ;remember size
DC.W $A51E ;allocate in system heap
BNE NoInstall ;if error, punt
MOVE.L A0,D2 ;remember base
MOVE.L A0,A1 ;that's the destination
MOVE.L A2,A0 ;AddResPatchis source
MOVE.L D1,D0 ;set up size
_BlockMove ;move it in
; patch in the new routine
MOVE.L D2,A0 ;get new address
MOVE.W #$14D,D0 ;trap ID of AddResMenu
_SetTrapAddress ;patch it in
; all done so exit to shell
_ExitToShell
; handle the error case by beeping
NoInstall
MOVE #6,-(SP)
_SysBeep
_ExitToShell